<!DOCTYPE html>
<html>
<head>
<title>Relativity Frames Diagram</title>
<style>
  body {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
    background-color: #f0f0f0;
  }
  canvas {
    border: 1px solid #ccc;
    background-color: white;
  }
</style>
</head>
<body>
<canvas id="relativityCanvas" width="850" height="400"></canvas>
<script>
  const canvas = document.getElementById('relativityCanvas');
  const ctx = canvas.getContext('2d');

  /**
   * Draws an arrow on the canvas context.
   * @param {CanvasRenderingContext2D} ctx - The canvas rendering context.
   * @param {number} fromX - The x-coordinate of the arrow's start point.
   * @param {number} fromY - The y-coordinate of the arrow's start point.
   * @param {number} toX - The x-coordinate of the arrow's end point.
   * @param {number} toY - The y-coordinate of the arrow's end point.
   * @param {number} [headLength=10] - The length of the arrowhead.
   */
  function drawArrow(ctx, fromX, fromY, toX, toY, headLength = 10) {
    const angle = Math.atan2(toY - fromY, toX - fromX);
    
    // Main line of the arrow
    ctx.beginPath();
    ctx.moveTo(fromX, fromY);
    ctx.lineTo(toX, toY);
    ctx.stroke();
    
    // Arrowhead
    ctx.beginPath();
    ctx.moveTo(toX, toY);
    ctx.lineTo(toX - headLength * Math.cos(angle - Math.PI / 6), toY - headLength * Math.sin(angle - Math.PI / 6));
    ctx.lineTo(toX - headLength * Math.cos(angle + Math.PI / 6), toY - headLength * Math.sin(angle + Math.PI / 6));
    ctx.closePath();
    ctx.fill();
  }

  // --- Style and Coordinate Constants ---
  ctx.strokeStyle = 'black';
  ctx.fillStyle = 'black';
  ctx.lineWidth = 2;

  const y_base = 250;
  const y_axis_top = 100;
  const x_origin_S = 150;
  const x_origin_S_prime = 250;
  const x_particle_Q = 500;
  const x_axis_end = 800;
  
  // --- Draw Axes ---
  // Horizontal x/x' axis
  drawArrow(ctx, x_origin_S - 100, y_base, x_axis_end, y_base);
  // Vertical y axis (S frame)
  drawArrow(ctx, x_origin_S, y_base + 20, x_origin_S, y_axis_top);
  // Vertical y' axis (S' frame)
  drawArrow(ctx, x_origin_S_prime, y_base + 20, x_origin_S_prime, y_axis_top);
  
  // --- Draw Labels ---
  ctx.textAlign = 'center';
  
  // Frame Labels
  ctx.font = '28px "KaiTi", "Times New Roman"';
  ctx.fillText('S系', x_origin_S - 50, y_axis_top + 40);
  ctx.fillText("S'系", x_origin_S_prime + 50, y_axis_top + 40);

  // Axis Labels
  ctx.font = 'italic 28px "Times New Roman"';
  ctx.textBaseline = 'bottom';
  ctx.fillText('y', x_origin_S, y_axis_top - 5);
  ctx.fillText("y'", x_origin_S_prime, y_axis_top - 5);
  
  ctx.textBaseline = 'top';
  ctx.fillText('x', x_axis_end - 40, y_base + 10);
  ctx.fillText("x'", x_axis_end - 10, y_base + 10);

  // Origin Labels
  ctx.fillText('O', x_origin_S, y_base + 10);
  ctx.fillText("O'", x_origin_S_prime, y_base + 10);
  
  // --- Draw Particles and their Labels ---
  const x_particle_P = x_origin_S_prime;

  // Particle P
  ctx.beginPath();
  ctx.arc(x_particle_P, y_base, 5, 0, Math.PI * 2);
  ctx.fill();
  
  // Particle Q
  ctx.beginPath();
  ctx.arc(x_particle_Q, y_base, 5, 0, Math.PI * 2);
  ctx.fill();

  // Particle Labels
  ctx.textBaseline = 'bottom';
  ctx.fillText('P', x_particle_P, y_base - 50);
  ctx.fillText('Q', x_particle_Q, y_base - 50);

  // Position Label for Q
  ctx.textBaseline = 'top';
  ctx.fillText("x' = L", x_particle_Q, y_base + 10);

  // --- Draw Vectors and their Labels ---
  // Velocity v of S' frame
  const v_y = y_base - 170;
  drawArrow(ctx, 550, v_y, 650, v_y);
  ctx.textBaseline = 'bottom';
  ctx.fillText('v', 600, v_y - 5);
  
  // Acceleration a0 of P
  const a0_start_x = x_particle_P + 10;
  const a0_end_x = x_particle_P + 130;
  drawArrow(ctx, a0_start_x, y_base, a0_end_x, y_base);
  const a0_label_x = (a0_start_x + a0_end_x) / 2;
  const a0_label_y = y_base - 10;
  ctx.fillText('a', a0_label_x, a0_label_y);
  ctx.font = 'italic 20px "Times New Roman"';
  ctx.fillText('0', a0_label_x + 10, a0_label_y + 2);

  // Velocity u of Q
  ctx.font = 'italic 28px "Times New Roman"';
  const u_start_x = x_particle_Q + 10;
  const u_end_x = x_particle_Q + 130;
  drawArrow(ctx, u_start_x, y_base, u_end_x, y_base);
  ctx.fillText('u', (u_start_x + u_end_x) / 2, y_base - 10);
</script>
</body>
</html>